#pragma once
#include <safeque.hxx>
#include <mythread.hxx>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <ctime>
#include "auto.hxx"
#include "autoerconstant.hxx"

using namespace std;

class Mutex;
class FileLog;
class GisusDB;
class Keyword;
class Watcher;
class User;
class SrvPerfWatcher;
class Action;
class CaptchaAction;
class CaptchaAction;
class BridgeConn;
class ProxyManager;
class DecaptcherUU;

class TaskManager : public Thread
{
public:
	////////////////////////////////////////////////////////////////////////////
	///////////////Constructor and Destructor///////////////////////////////////
	TaskManager(const User* user, GisusDB* gisusdb, DMFun f = NULL, FileLog* filelog = NULL);
	~TaskManager();

	const char* GetCaptcha(size_t& size, bool& urgent);
	bool SetCaptcha(const string& captcha);

	void Shutdown(void);

	const Task* SetPTask(const string& cjh);
	void SetQueryVL(int interval);
	void SetMode(Auto::ModeKind mode);

	void StartQuery(bool start);
	void SetTotalCountZxrs(long newTotalCount, long newZxrs);

	Action* GetReadyAction(void);

	const string GetGoodPort(void) const;
	void RePorts(const std::vector<std::string> slowPorts);
	Task* GetASeed(void);
	bool IsBusy(string* why=NULL) const;

	void ResetLastWatched(void);
	bool ReleaseTask(const string& cjh);

	int Decode(char* image, int inLen, string& result);
	int Refund(int id);

	DMFun DisplayMsg;

private:
	friend class Task;
	friend class Watcher;

	string GetProxy(void);
	void InvalidProxy(const string& proxy);
	
	void AddWCaptcha(CaptchaAction* Action, bool highPriority = false);
	void ToExecute(Action* Action, bool highPriority = false);

	void MatchResult(const std::string& result, const std::string& chooseUrl, Task* owner);
	void MatchResults(const std::map<string, string>& results, Task* owner = NULL);
	void DisplayResults(const std::map<string, string>& results);

	void ReportResults(const std::vector<string>& results);
	void ReportProxies(const std::vector<string>& proxies);

	void PreAction(Action* Action);
	void AfterAction(Action* Action);

	virtual void Execute(Thread::Arg);

	ProxyManager* proxyManager;
	BridgeConn* bridgeConn;
	DecaptcherUU* decaptcher;

	SafeQue<CaptchaAction*> wCaptchas;
	SafeQue<CaptchaAction*> wPCaptchas;
	SafeQue<CaptchaAction*> wHCaptchas;
	SafeQue<Action*> readyActions;
	SafeQue<Action*> readyHActions;

	mutable Mutex pTasksInUse;
	std::vector<Task*> pTasks;
	std::vector<Task*>::iterator pTaskCurIter;

	mutable Mutex apTasksInUse;
	std::vector<Task*> apTasks;

	mutable Mutex zombiesInUse;
	std::vector<Task*> zombies;
	std::vector<Task*>::iterator zombieCurIter;

	mutable Mutex attackersInUse;
	std::vector<Task*> attackers;

	std::set<std::string> existingResults;

	mutable Mutex kwdsSetInUse;
	std::map<std::string, unsigned int> kwdsSet;
	std::map<std::string, unsigned int>::iterator kwdsSetCurIter;
	bool scanning;

	long readyZombieNum;
	long readyPTaskNum;

	CaptchaAction* curCaptchaAction;

	const User* user;
	GisusDB* gisusdb;
	Auto::ModeKind mode;
	bool isShuai3Tong;
	bool isShuaiDuizi;

	bool queryStarted;
	int queryInterval;

	long totalCount;
	long zxrs;

	time_t lastWatched;

	bool isShutdownRequested;
	FileLog* _filelog;

	//////////////////////////////////////////////////////////////////////
	void HandleWatched(int num = 0, int curAll = 0);

	Action* GetQAction(const string& spec, const string& avoidchars1 = "4");
	std::string NextSpec(void);
	void ReCreateSpecSet(bool notify = true);
	void MatchPTasks(const string& result, const string& chooseUrl);

	void ReleaseTasks(std::vector<Task*>& tasks, Mutex& theLock);
	int PrepareTasks(std::vector<Task*>& tasks, Mutex& theLock);

	bool IsPTaskReady(void) const;

	void LoadAPTasks(const string& spec);
	void DisplayPTasks(void) const;

	int LoadZombies(int num, std::vector<Task*>& zombies);

	void SyncCaptchaNum(void);
	void DumpStatistics(const Task* task = NULL);
	bool NextAction(Task* task);
	
	void IncreCaptchaNum(bool isIncre = true, bool isPTask = false);


	/////////////////////////////////////////////////
	// for creating new zombies.
	static std::string GetCjhForZombie(const string& cjhRooti, int index=0);
	void CreateZombies();
};